﻿//++
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// Module Name:
//
//  GetFolderTask.cs
//    
// Abstract:
//
//  This module implements the GetFolderTask class. This handles the task of getting a folder via EWS.
//
//--

using System;
using System.Collections.Generic;
using System.Diagnostics;

using Microsoft.OfficeCommunicationsServer.Applications.Common;

namespace Microsoft.EnhancedReminders.Scheduler
{
    /// <summary>
    /// This handles the task of getting a folder via EWS.
    /// </summary>
    internal abstract class GetFolderTask : ExchangeTask
    {
        // IDs of folders to be got
        protected BaseFolderIdType[] _folderIds;

        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="taskContext">Task context</param>
        /// <param name="client">WCF proxy for communicating with EWS</param>
        /// <param name="impersonation">Exchange impersonation info</param>
        /// <param name="emailAddress">E-mail address of the user associated with this request</param>
        protected GetFolderTask(TaskContext taskContext, ExchangeServicePortType client, ExchangeImpersonationType impersonation, string emailAddress)
            : base(taskContext, client, impersonation, emailAddress)
        {
        }

        /// <summary>
        /// Request the folders associated with this task.
        /// </summary>
        internal override void Begin()
        {
            Debug.Assert(_folderIds != null, "_folderIds != null");
            Debug.Assert(_folderIds.Length > 0, "_folderIds.Length > 0");

            Logger.WriteTraceVerbose(Context, "GetFolderTask.Begin");

            GetFolderType getFolder = new GetFolderType();
            getFolder.FolderIds = _folderIds;
            getFolder.FolderShape = new FolderResponseShapeType();
            getFolder.FolderShape.BaseShape = DefaultShapeNamesType.IdOnly;

            GetFolderRequest getFolderRequest = new GetFolderRequest();
            getFolderRequest.ExchangeImpersonation = _impersonation;
            getFolderRequest.RequestServerVersion = ExchangeUsers.RequestServerVersion;
            getFolderRequest.GetFolder = getFolder;

            try
            {
                // Get the specified folders via EWS
                _client.BeginGetFolder(getFolderRequest, OnGetFolderCompleted, null);
            }
            catch (Exception ex)
            {
                HandleAccessError(ex, "BeginGetFolder failed.");
            }
        }

        protected abstract void OnGetFolderCompleted(IAsyncResult asyncResult);
    }

    internal class GetDistinguishedFolderTask : GetFolderTask
    {
        private readonly DistinguishedFolderIdNameType[] _distinguishedFolderIdNames;

        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="taskContext">Task context</param>
        /// <param name="client">WCF proxy for communicating with EWS</param>
        /// <param name="impersonation">Exchange impersonation info</param>
        /// <param name="emailAddress">E-mail address of the user associated with this request</param>
        /// <param name="distinguishedFolderIdNames">Distinguished folder names</param>
        internal GetDistinguishedFolderTask(TaskContext taskContext, ExchangeServicePortType client, ExchangeImpersonationType impersonation, string emailAddress, DistinguishedFolderIdNameType[] distinguishedFolderIdNames)
            : base(taskContext, client, impersonation, emailAddress)
        {
            Debug.Assert(distinguishedFolderIdNames != null, "distinguishedFolderIdNames != null");
            Debug.Assert(distinguishedFolderIdNames.Length > 0, "distinguishedFolderIdNames.Length > 0");

            _distinguishedFolderIdNames = distinguishedFolderIdNames;
            _folderIds = new BaseFolderIdType[_distinguishedFolderIdNames.Length];

            EmailAddressType mailbox = new EmailAddressType();
            mailbox.EmailAddress = _emailAddress;

            for (int folderIndex = 0; folderIndex < _distinguishedFolderIdNames.Length; folderIndex++)
            {
                DistinguishedFolderIdType id = new DistinguishedFolderIdType();
                id.Id = _distinguishedFolderIdNames[folderIndex];
                id.Mailbox = mailbox;
                _folderIds[folderIndex] = id;
            }
        }

        /// <summary>
        /// Handles completion of the EWS request to get the folders associated with this task.
        /// </summary>
        /// <param name="asyncResult">Status of the asynchronous operation</param>
        protected override void OnGetFolderCompleted(IAsyncResult asyncResult)
        {
            Logger.WriteTraceVerbose(Context, "GetDistinguishedFolderTask.OnGetFolderCompleted");

            GetFolderResponse getFolderResponse = GetResponse<GetFolderResponse>(asyncResult, _client.EndGetFolder, "EndGetFolder failed.");

            if (getFolderResponse == null)
            {
                return;
            }

            Dictionary<FolderIdType, DistinguishedFolderIdNameType> folderIdTable = new Dictionary<FolderIdType, DistinguishedFolderIdNameType>();

            ResponseMessageType[] responseMessages = getFolderResponse.GetFolderResponse1.ResponseMessages.Items;
            Debug.Assert(responseMessages != null, "responseMessages != null");
            Debug.Assert(responseMessages.Length == _distinguishedFolderIdNames.Length, "responseMessages.Length == _distinguishedFolderIdNames.Length");

            // For each response message create a dictionary entry mapping the actual folder ID for the folder to the 
            // distinguished folder id name. Note that responses always match the order of the request so it is okay 
            // just to iterate across the values and they should match up.
            for (int folderIndex = 0; folderIndex < responseMessages.Length; folderIndex++)
            {
                FolderInfoResponseMessageType folderInfoMessage = responseMessages[folderIndex] as FolderInfoResponseMessageType;

                if (folderInfoMessage.ResponseClass == ResponseClassType.Success)
                {
                    // Note that each response message will always hold zero or one folders
                    folderIdTable.Add(folderInfoMessage.Folders[0].FolderId, _distinguishedFolderIdNames[folderIndex]);
                }
                else
                {
                    // The distinguished folder IDs are critical so this is an unrecoverable error for this user
                    Logger.WriteTraceError(Context, "Failed to retrieve distinguished folder ID for '{0}'.", _distinguishedFolderIdNames[folderIndex]);
                    RaiseCompleted(new TaskCompletedEventArgs(_taskContext, new ExchangeTaskFailedException(Context, folderInfoMessage.ResponseCode, "Failed to retrieve distinguished folder ID.")));
                    return;
                }
            }

            Debug.Assert(folderIdTable.Count == _distinguishedFolderIdNames.Length, "folderIdTable.Count == _distinguishedFolderIdNames.Length");
            Logger.WriteTraceInformation(Context, "Retrieved distinguished folder IDs.");
            RaiseCompleted(new GetDistinguishedFolderTaskCompletedEventArgs(_taskContext, folderIdTable));
        }
    }
}
